package engine.systems.ui.screenAlign
{
	import ash.core.Engine;
	import ash.core.NodeList;
	import ash.core.System;
	
	import engine.GameEngine;
	import engine.classes.enumerations.Margin;
	import engine.classes.enumerations.SystemPriority;
	import engine.managers.ScreenManager;
	
	import flash.display.Stage;
	
	/**
	 * The Screen Align System repositions and resizes UI Display Objects so they're correctly
	 * positioned onscreen.
	 * 
	 * @see MarginAlign
	 * @see MarginAlignNode
	 * @see BoxAlign
	 * @see BoxAlignNode
	 */
	public class ScreenAlignSystem extends System
	{
		private const _stage:Stage 	= GameEngine.screenManager.stage;
		private var oldWidth:int 	= 0;
		private var oldHeight:int 	= 0;
		
		private var width:Number 	= 0;
		private var height:Number 	= 0;
		
		private var boxes:NodeList;
		private var margins:NodeList;
		
		public function ScreenAlignSystem()
		{	
			this.priority = SystemPriority.UPDATE;
		}
		
		override public function update(time:Number):void
		{
			//Get the current width and height of the screen.
			width 	= _stage.stageWidth;
			height 	= _stage.stageHeight;
			
			//If nothing's changed, don't update anything.
			if(oldWidth == width && oldHeight == height) return;
			
			//Set the old width and height to the new ones.
			oldWidth 	= width;
			oldHeight 	= height;
			
			this.alignMargins();
			this.alignBoxes();
		}
	
		private function alignMargins():void
		{
			for(var node:MarginAlignNode = this.margins.head; node; node = node.next)
			{
				switch(node.align.margin)
				{
					case Margin.UPPER_LEFT:
						node.spatial.x = 0;
						node.spatial.y = 0;
						break;
					
					case Margin.UPPER_MIDDLE:
						node.spatial.x = width * 0.5;
						node.spatial.y = 0;
						break;
					
					case Margin.UPPER_RIGHT:
						node.spatial.x = width;
						node.spatial.y = 0;
						break;
					
					case Margin.MIDDLE_LEFT:
						node.spatial.x = 0;
						node.spatial.y = height * 0.5;
						break;
					
					case Margin.MIDDLE:
						node.spatial.x = width * 0.5;
						node.spatial.y = height * 0.5;
						break;
					
					case Margin.MIDDLE_RIGHT:
						node.spatial.x = width;
						node.spatial.y = height * 0.5;
						break;
					
					case Margin.LOWER_LEFT:
						node.spatial.x = 0;
						node.spatial.y = height;
						break;
					
					case Margin.LOWER_MIDDLE:
						node.spatial.x = width * 0.5;
						node.spatial.y = height;
						break;
					
					case Margin.LOWER_RIGHT:
						node.spatial.x = width;
						node.spatial.y = height;
						break;
					
					default:
						throw new Error("ScreenAlignSystem :: Invalid margin for " + node.entity.name + " entity!");
						break;
				}
				
				node.spatial.x += node.align.offsetX;
				node.spatial.y += node.align.offsetY;
			}
		}
		
		private function alignBoxes():void
		{
			for(var node:BoxAlignNode = this.boxes.head; node; node = node.next)
			{
				node.render.display.width 	= width;
				node.render.display.height 	= height;
				
				/**
				 * After changing the width and height, you need to set the Spatial scale,
				 * otherwise the old Spatial scale will override the new size.
				 */
				node.spatial.scaleX = node.render.display.scaleX;
				node.spatial.scaleY = node.render.display.scaleY;
			}
		}
		
		override public function addToEngine(systemManager:Engine):void
		{
			this.margins 	= systemManager.getNodeList(MarginAlignNode);
			this.boxes 		= systemManager.getNodeList(BoxAlignNode);
		}
		
		override public function removeFromEngine(systemManager:Engine):void
		{
			systemManager.releaseNodeList(MarginAlignNode);
			systemManager.releaseNodeList(BoxAlignNode);
			this.margins 	= null;
			this.boxes 		= null;
		}
	}
}